/*
 * Copyright (c) 2008 VMware, Inc.
 * Copyright (c) 2009 John Pritchard, WTKX Project Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package wtkx;

import wtkx.collections.ArrayList;
import wtkx.collections.Sequence;
import wtkx.util.ImmutableIterator;
import wtkx.util.ListenerList;
import wtkx.wtk.MenuItemSelectionListener;
import wtkx.wtk.MenuListener;
import wtkx.wtk.content.MenuItemDataDecorator;

import java.util.Iterator;

/**
 * Component that presents a cascading menu.
 *
 * @author gbrown
 */
public class Menu
    extends Container
{
    /**
     * Item listener interface.
     *
     * @author gbrown
     */
    public interface ItemListener {
        public void menuChanged(MenuItem item, Menu previousMenu);
    }

    /**
     * Section sequence implementation.
     *
     * @author gbrown
     */
    public final class SectionSequence
        implements Sequence<MenuSection>, Iterable<MenuSection> 
    {
        SectionSequence() {
            super();
        }

        public int add(MenuSection section) {
            int index = getLength();
            insert(section, index);

            return index;
        }

        public void insert(MenuSection section, int index) {
            if (section.getMenu() != null) {
                throw new IllegalArgumentException("section already has a menu.");
            }

            sections.insert(section, index);
            section.setMenu(Menu.this);

            for (int i = 0, n = section.getLength(); i < n; i++) {
                Menu.this.add(section.get(i));
            }

            menuListeners.sectionInserted(Menu.this, index);
        }

        public MenuSection update(int index, MenuSection section) {
            throw new UnsupportedOperationException();
        }

        public int remove(MenuSection section) {
            int index = sections.indexOf(section);
            if (index != -1) {
                remove(index, 1);
            }

            return index;
        }

        public Sequence<MenuSection> remove(int index, int count) {
            Sequence<MenuSection> removed = sections.remove(index, count);

            for (int i = 0, n = removed.getLength(); i < n; i++) {
                MenuSection section = removed.get(i);

                section.setMenu(null);

                for (MenuItem item : section) {
                    Menu.this.remove(item);
                }
            }

            menuListeners.sectionsRemoved(Menu.this, index, removed);

            return removed;
        }

        public MenuSection get(int index) {
            return sections.get(index);
        }

        public int indexOf(MenuSection item) {
            return sections.indexOf(item);
        }

        public int getLength() {
            return sections.getLength();
        }

        public Iterator<MenuSection> iterator() {
            return new ImmutableIterator<MenuSection>(sections.iterator());
        }
    }

    public static class MenuListenerList
        extends ListenerList<MenuListener>
        implements MenuListener 
    {
        MenuListenerList(){
            super();
        }

        public void sectionInserted(Menu menu, int index) {
            for (MenuListener listener : this) {
                listener.sectionInserted(menu, index);
            }
        }

        public void sectionsRemoved(Menu menu, int index, Sequence<MenuSection> removed) {
            for (MenuListener listener : this) {
                listener.sectionsRemoved(menu, index, removed);
            }
        }

        public void itemInserted(MenuSection section, int index) {
            for (MenuListener listener : this) {
                listener.itemInserted(section, index);
            }
        }

        public void itemsRemoved(MenuSection section, int index, Sequence<MenuItem> removed) {
            for (MenuListener listener : this) {
                listener.itemsRemoved(section, index, removed);
            }
        }
    }

    public static class MenuItemSelectionListenerList 
        extends ListenerList<MenuItemSelectionListener>
        implements MenuItemSelectionListener 
    {
        MenuItemSelectionListenerList(){
            super();
        }

        public void itemSelected(MenuItem menuItem) {
            for (MenuItemSelectionListener listener : this) {
                listener.itemSelected(menuItem);
            }
        }
    }

    MenuItem item = null;
    private ArrayList<MenuSection> sections = new ArrayList<MenuSection>();
    private SectionSequence sectionSequence = new SectionSequence();

    private MenuListenerList menuListeners = new MenuListenerList();
    private MenuItemSelectionListenerList menuItemSelectionListeners = new MenuItemSelectionListenerList();


    public Menu() {
        installSkin(Menu.class);
    }

    public MenuItem getItem() {
        return item;
    }

    public void setItem(MenuItem item) {
        this.item = item;
    }

    public SectionSequence getSections() {
        return sectionSequence;
    }

    @Override
    public Sequence<Component> remove(int index, int count) {
        for (int i = index, n = index + count; i < n; i++) {
            MenuItem item = (MenuItem)get(i);

            if (item.getSection() != null) {
                throw new UnsupportedOperationException();
            }
        }

        // Call the base method to remove the components
        return super.remove(index, count);
    }

    public MenuListenerList getMenuListeners() {
        return menuListeners;
    }

    public MenuItemSelectionListenerList getMenuItemSelectionListeners() {
        return menuItemSelectionListeners;
    }
}
